package com.easylinkin.linkappapi.ruleengine.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.intelligentrule.entity.IntelligentRuleExpression;
import com.easylinkin.linkappapi.intelligentrule.service.IntelligentRuleExpressionService;
import com.easylinkin.linkappapi.ruleengine.constant.RuleConditionConstant;
import com.easylinkin.linkappapi.ruleengine.entity.RuleCondition;
import com.easylinkin.linkappapi.ruleengine.mapper.RuleConditionMapper;
import com.easylinkin.linkappapi.ruleengine.service.RuleConditionService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 条件器 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2020-08-24
 */
@Service
public class RuleConditionServiceImpl extends ServiceImpl<RuleConditionMapper, RuleCondition> implements RuleConditionService {


    private static final Logger LOGGER = LoggerFactory.getLogger(RuleConditionServiceImpl.class);

    @Resource
    private CommonService commonService;
    @Resource
    private IntelligentRuleExpressionService intelligentRuleExpressionService;
    @Resource
    private DeviceService deviceService;
    @Resource
    private DeviceAttributeStatusService deviceAttributeStatusService;


    @Override
    public void add(RuleCondition ruleCondition) {
        validParamRequired(ruleCondition);
        validParamFormat(ruleCondition);
        validRepeat(ruleCondition);
        if (RuleConditionConstant.TIME_RANGE_TYPE.equals(ruleCondition.getType())) {
            Assert.hasLength(ruleCondition.getTimeScopeCron(), "type为1 timeScopeCron不能为空");
        } else {
            ruleCondition.setTimeScopeCron(null);
        }
        Date now = new Date();
        ruleCondition.setCreateTime(now);
        ruleCondition.setModifyTime(now);
        ruleCondition.setSortFlag(DateUtil.getyyyyMMddHHmmssSSSNumberString(now));

        save(ruleCondition);

        if (RuleConditionConstant.DEVICE_STATUS_TYPE.equals(ruleCondition.getType())) {
            List<IntelligentRuleExpression> intelligentRuleExpressions = ruleCondition.getIntelligentRuleExpressionList();
            Assert.notEmpty(intelligentRuleExpressions,"条件器type为2时，intelligentRuleExpressions不能为空！");
            for (IntelligentRuleExpression intelligentRuleExpression : intelligentRuleExpressions) {
                intelligentRuleExpression.setRuleConditionId(ruleCondition.getId());
                intelligentRuleExpressionService.save(intelligentRuleExpression);
            }
        }

    }


    /**
     * 校验重复
     */
    private void validRepeat(RuleCondition ruleCondition) {
    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(RuleCondition ruleCondition) {
        Assert.notNull(ruleCondition, "参数为空");
        Assert.notNull(ruleCondition.getType(), "参数中条件类型为空");
        Assert.isTrue(StringUtils.isNotBlank(ruleCondition.getRuleEngineId()), "getRuleEngineId 为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(RuleCondition ruleCondition) {
        Assert.isTrue(ruleCondition.getSortFlag() == null || ruleCondition.getSortFlag().length() <= 20, "getSortFlag 超长");
        Assert.isTrue(ruleCondition.getRuleEngineId() == null || ruleCondition.getRuleEngineId().length() <= 32, "getRuleEngineId 超长");
        Assert.isTrue(ruleCondition.getDeviceCode() == null || ruleCondition.getDeviceCode().length() <= 32, "getDeviceCode 超长");
        Assert.isTrue(ruleCondition.getTimeScopeCron() == null || ruleCondition.getTimeScopeCron().length() <= 120, "时间范围cron表达式 超长");
    }

    @Override
    public List<RuleCondition> getRuleConditions(RuleCondition ruleCondition) {
        return baseMapper.getRuleConditions(ruleCondition);
    }

    @Override
    public List<RuleCondition> getRuleConditionWithExpressions(RuleCondition ruleCondition) {
        return baseMapper.getRuleConditionWithExpressions(ruleCondition);
    }

    @Override
    public IPage<RuleCondition> getRuleConditions(Page page, RuleCondition ruleCondition) {
        return baseMapper.getRuleConditions(page, ruleCondition);
    }

    @Override
    public RuleCondition getRuleCondition(String id) {
        RuleCondition record = baseMapper.getRuleCondition(id);
        return record;
    }


/*    @Override
    public void updateRuleCondition(RuleCondition ruleCondition) {
        Assert.notNull(ruleCondition, "参数为空");
        RuleCondition originRuleCondition = getById(ruleCondition.getId());
        Assert.notNull(originRuleCondition, "原条件器不存在");
        validRepeat(ruleCondition);
        validParamFormat(ruleCondition);
        commonService.setModifyInfo(ruleCondition);
        updateById(ruleCondition);

        updateExpressionForRuleChange(ruleCondition);
    }*/

    /**
     * 条件器修改  相应修改其对应规则表达式
     *
     * @param ruleCondition 条件器
     */
    public void updateExpressionForRuleChange(RuleCondition ruleCondition) {
        if (!RuleConditionConstant.DEVICE_STATUS_TYPE.equals(ruleCondition.getType())) {
            return;
        }
        //若 规则表达式为null 跳过下面操作,接口可能来自 启用-停用操作,编辑操作此参一定不为空
        if (null == ruleCondition.getIntelligentRuleExpressionList()) {
            return;
        }
        //删除 旧的表达式
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("rule_condition_id", ruleCondition.getId());
        List<String> list = intelligentRuleExpressionService.listObjs(queryWrapper.select("id"));

        intelligentRuleExpressionService.deleteForceByIds(list);

        List<IntelligentRuleExpression> intelligentRuleExpressions = ruleCondition.getIntelligentRuleExpressionList();

        if (!CollectionUtils.isEmpty(ruleCondition.getIntelligentRuleExpressionList())) {
            for (IntelligentRuleExpression intelligentRuleExpression : intelligentRuleExpressions) {
//                intelligentRuleExpression.setIntelligentRuleId(ruleCondition.getId());
                intelligentRuleExpression.setRuleConditionId(ruleCondition.getId());
            }
            intelligentRuleExpressionService.saveOrUpdateBatch(intelligentRuleExpressions);
        }
    }

    @Override
    public void deleteBatch(List<RuleCondition> ruleConditionList) {
        if (ObjectUtils.isEmpty(ruleConditionList)) {
            return;
        }
        List<String> ids = ruleConditionList.stream().map(RuleCondition::getId).filter(id -> StringUtils.isNotEmpty(id)).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(ids)) {
            return;
        }
        removeByIds(ids);

        QueryWrapper<IntelligentRuleExpression> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("rule_condition_id", ids);
        intelligentRuleExpressionService.remove(queryWrapper);
    }

    @Override
    public List<RuleCondition> getRuleConditionsInRuleEngineIds(Set<String> meetRuleTriggerRuleEngineIds) {
        if (ObjectUtils.isEmpty(meetRuleTriggerRuleEngineIds)) {
            return null;
        }
        RuleCondition ruleCondition = new RuleCondition();
        ruleCondition.setRuleEngineIds(meetRuleTriggerRuleEngineIds);
        return getRuleConditionWithExpressions(ruleCondition);
    }

    @Override
    public Set<String> getMeetRuleConditionRuleEngineIds(Set<String> meetedRuleEngineIds) {
        HashMap<String, Boolean> ruleEngineId2meet = new HashMap<>();
        for (String meetedRuleEngineId : meetedRuleEngineIds) {
            ruleEngineId2meet.put(meetedRuleEngineId, true);
        }
        List<RuleCondition> ruleConditionList = getRuleConditionsInRuleEngineIds(meetedRuleEngineIds);
        for (RuleCondition ruleCondition : ruleConditionList) {
            if (ruleEngineId2meet.get(ruleCondition.getRuleEngineId())) {
                boolean b = isMeetRuleCondition(ruleCondition);
                if (!b) {
                    ruleEngineId2meet.put(ruleCondition.getRuleEngineId(), false);
                }
            }
        }
        Set<String> meetRuleEngineIds = new HashSet<>();
        ruleEngineId2meet.forEach((k, v) -> {
            if (v) {
                meetRuleEngineIds.add(k);
            }
        });
        return meetRuleEngineIds;
    }

    private boolean isMeetRuleCondition(RuleCondition ruleCondition) {
        if (RuleConditionConstant.TIME_RANGE_TYPE.equals(ruleCondition.getType())) {
            if (ObjectUtils.isEmpty(ruleCondition.getTimeScopeCron())) {
                return false;
            }
            CronExpression cronExpression = null;
            try {
                cronExpression = new CronExpression(ruleCondition.getTimeScopeCron());
            } catch (ParseException ex) {
                LOGGER.error("发生cron 表达式解析异常，智能规则为：{}", JSONObject.toJSONString(ruleCondition), ex);
            }
            if (cronExpression == null || !cronExpression.isSatisfiedBy(new Date())) {
                LOGGER.info("检查不满足时间范围：{}", JSONObject.toJSONString(ruleCondition));
                return false;
            }
        } else if (RuleConditionConstant.DEVICE_STATUS_TYPE.equals(ruleCondition.getType())) {
            Device device = deviceService.findOneByDeviceCode(ruleCondition.getDeviceCode());
            if (ObjectUtils.isEmpty(device)) {
                return false;
            }
            device.setDeviceAttributeStatusList(deviceAttributeStatusService.getLatestDeviceAttributeStatusList(device.getCode(), null));
            if (!intelligentRuleExpressionService.checkMeetExpressions(device, ruleCondition.getIntelligentRuleExpressionList())) {
                return false;
            }
        } else {
            LOGGER.warn("未知的规则条件状态：{}", ruleCondition.getRuleEngineId());
            return false;
        }
        return true;
    }

    @Test
    public void test() {
        while (true) {
            try {
                Calendar calendar = Calendar.getInstance();
                calendar.set(Calendar.HOUR_OF_DAY, RandomUtils.nextInt(0, 7));
                calendar.set(Calendar.MINUTE, RandomUtils.nextInt(0, 59));
                Date date = calendar.getTime();
                CronExpression cronExpression = new CronExpression("0-59 * 8-18 * * ? *");
                boolean b = cronExpression.isSatisfiedBy(date);
                if (b) {
                    System.out.println(b);
                }
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
    }


}

